package cn.wizzer.app.crown.modules.services.impl.order;

import cn.wizzer.app.crown.modules.models.*;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.enums.PlayWayEnum;
import cn.wizzer.app.crown.modules.models.enums.SettleStatusEnum;
import cn.wizzer.app.crown.modules.services.CrownLeagueService;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.CrownSubResultService;
import cn.wizzer.app.crown.modules.services.FTSettleService;
import cn.wizzer.app.crown.modules.services.order.CrownOrderDetailService;
import cn.wizzer.app.crown.modules.services.order.CrownOrderService;
import cn.wizzer.app.crown.modules.services.result.LeagueResultService;
import cn.wizzer.app.sys.modules.models.SysMsg;
import cn.wizzer.app.sys.modules.services.SysMsgService;
import cn.wizzer.app.user.modules.models.UserAccount;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.vo.UserAccountVo;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.app.user.modules.services.account.UserAccountService;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.exceptions.BizException;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.notify.WkNotifyUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@IocBean
@Service(interfaceClass = FTSettleService.class)
public class FTSettleServiceImpl implements FTSettleService {
    @Inject
    private CrownMatchService matchService;
    @Inject
    private CrownLeagueService leagueService;
    @Inject
    private CrownSubResultService subResultService;
    @Inject
    private LeagueResultService leagueResultService;
    @Inject
    private CommonDBService commondbservice;
    @Inject
    private CrownOrderService orderService;
    @Inject
    private CrownOrderDetailService orderDetailService;
    @Reference(retries = 0)
    @Inject
    private UserAccountRecordService recordService;
    @Inject
    @Reference
    private UserAccountService accountService;
    @Inject
    @Reference
    private SysMsgService sysMsgService;
    @Inject
    @Reference
    private WkNotifyUtil wkNotifyUtil;

    @Override
    public void settle(CrownOrder order) {
        // 单式结算
        if (PlayWayEnum.R.equals(order.getPlayWay())) {
            // 订单详情
            CrownOrderDetail orderDetail = orderDetailService.fetch(Cnd.where("order_id", "=", order.getId()));
            order.setDetails(Result.createList(orderDetail));
            // 关联赛事
            CrownMatch match = matchService.fetch(orderDetail.getGameId());
            // 结算订单
            this.simplexSettle(order, match);
        }
        // 综合结算
        else if (PlayWayEnum.P3.equals(order.getPlayWay())) {
            this.complexSettle(order);
        }
        // 冠军订单
        else if (PlayWayEnum.FS.equals(order.getPlayWay())) {
            // 查询订单详情
            CrownOrderDetail orderDetail = orderDetailService.fetch(Cnd.where("order_id", "=", order.getId()));
            order.setDetails(Result.createList(orderDetail));
            // 查询关联的联赛
            CrownLeague league = leagueService.fetch(orderDetail.getGameId());
            this.championSettle(order, league);
        }
    }

    @Override
    public void reSettle(CrownMatch match) {
        // todo 如果是‘第二次’重新结算，要删掉‘第一次’重新结算的记录，否则表的唯一索引导致插不进去
        // 查询该赛事相关并且订单已经结算的orderDetail集合
        Sql sql = Sqls.create("SELECT od.* FROM crown_order_detail AS od LEFT JOIN crown_order AS o ON od.order_id = o.id")
                .appendSourceSql("WHERE o.status = @status and od.game_id = @matchId")
                .setParam("status", SettleStatusEnum.SETTLED)
                .setParam("matchId", match.getId());
        List<CrownOrderDetail> orderDetails = commondbservice.list(CrownOrderDetail.class, sql.toString());
        // 记录订单旧的输赢状态
        SettleStatusEnum oldStatus;
        // 重新计算订单输赢
        for (CrownOrderDetail orderDetail : orderDetails) {
            // 新的赛事状态是other
            if (CrownConstant.OTHER.equals(match.getStage())) {
                // 查询出订单并扣除结算金额
                CrownOrder order = this.deductResultAmount(orderDetail);
                if (PlayWayEnum.P3.equals(order.getPlayWay())) {
                    // 综合订单重新结算
                    this.complexSettle(order);
                } else {
                    orderDetail.setStatus(SettleStatusEnum.CANCELLED);
                    // 单式订单回退下注金额
                    this.handleRefundOrder(order);
                }
            }
            // 新的赛事状态是finished
            else {
                // 记录旧的订单条目结算状态
                oldStatus = orderDetail.getStatus();
                // 重新计算输赢
                this.calSimplexStatus(orderDetail, match);
                // 如果重新计算的输赢状态发生变化，重新结算该笔订单
                if (!oldStatus.equals(orderDetail.getStatus())) {
                    // 查询出订单并扣除结算金额
                    CrownOrder order = this.deductResultAmount(orderDetail);
                    if (PlayWayEnum.R.equals(order.getPlayWay())) {
                        // 单式订单重新结算
                        this.simplexSettle(order, match);
                    } else {
                        // 综合订单重新结算
                        this.complexSettle(order);
                    }
                    // 如果用户余额为负数，后台发送消息通知。
                    this.sendSysMsg(order);
                }
            }
        }
    }


    @Override
    public void reSettle(CrownLeague league) {
        // todo 如果是‘第二次’重新结算，是否要删掉‘第一次’重新结算的记录，否则表的唯一索引导致插不进去
        // 查询该联赛下已结算的订单
        Sql sql = Sqls.create("SELECT od.* FROM crown_order_detail AS od LEFT JOIN crown_order AS o ON od.order_id = o.id")
                .appendSourceSql("WHERE o.status = @status and od.game_id = @leagueId")
                .setParam("status", SettleStatusEnum.SETTLED)
                .setParam("leagueId", league.getId());
        List<CrownOrderDetail> orderDetails = commondbservice.list(CrownOrderDetail.class, sql.toString());
        // 记录订单旧的输赢状态
        SettleStatusEnum oldStatus;
        // 重新计算订单输赢
        for (CrownOrderDetail orderDetail : orderDetails) {
            // 新的状态是other
            if (CrownConstant.OTHER.equals(league.getStage())) {
                // 查询出订单并扣除结算金额
                CrownOrder order = this.deductResultAmount(orderDetail);
                // 回退下注金额
                orderDetail.setStatus(SettleStatusEnum.CANCELLED);
                // 单式订单回退下注金额
                this.handleRefundOrder(order);
            }
            // 新的赛事状态是finished
            else {
                // 记录旧的订单条目结算状态
                oldStatus = orderDetail.getStatus();
                // 重新计算输赢
                this.calChampionStatus(orderDetail, league);
                // 如果重新结算的输赢状态不相同，则重新结算。
                if (!oldStatus.equals(orderDetail.getStatus())) {
                    // 查询出订单并扣除结算金额
                    CrownOrder order = this.deductResultAmount(orderDetail);
                    // 重新结算
                    this.championSettle(order, league);
                    // 如果用户余额为负数，后台发送消息通知。
                    this.sendSysMsg(order);
                }
            }
        }
    }

    /**
     * 查询用户账户是否为负数，发送后台消息
     *
     * @param order
     */
    private void sendSysMsg(CrownOrder order) {
        UserAccount userAccount = accountService.selectByUserId(order.getUserId());
        if (userAccount.getTotal().compareTo(BigDecimal.ZERO) < 0) {
            Sql accountSql = Sqls.create("SELECT a.*,u.`nickName`,u.`phone` FROM user_account AS a LEFT JOIN USER AS u ON u.id = a.user_id")
                    .appendSourceSql("WHERE u.id = @userId")
                    .setParam("userId", order.getUserId());
            UserAccountVo userAccountVo = commondbservice.fetchSql(UserAccountVo.class, accountSql.toString());
            //构建消息通知
            SysMsg msg = sysMsgService.createMsg("system", "账变导致用户账户金额为负数",
                    "相关订单号:" + order.getNo() + "用户账户信息:" + userAccountVo.toString(), null);
            //插入通知
            sysMsgService.saveMsg(msg, null);
            //后台通知管理员
            wkNotifyUtil.notify(msg, null);
        }
    }

    /**
     * 查询order，并扣除结算金额
     *
     * @param orderDetail
     * @return
     */
    private CrownOrder deductResultAmount(CrownOrderDetail orderDetail) {
        CrownOrder order = orderService.fetch(orderDetail.getOrderId());
        order.setDetails(Result.createList(orderDetail));
        // 结算金额大于0则扣除
        if (order.getResultAmount().compareTo(BigDecimal.ZERO) > 0) {
            // 扣除结算金额
            recordService.add(order.getUserId(), order.getResultAmount(), BizTypeEnum.BALL_DEDUCT, order.getId());
        }
        return order;
    }

    /**
     * 冠军订单结算
     *
     * @param order
     * @param league
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void championSettle(CrownOrder order, CrownLeague league) {
        CrownOrderDetail orderDetail = order.getDetails().get(0);
        // 如果赛事状态为other，退回下注金额
        if (CrownConstant.OTHER.equals(league.getStage())) {
            orderDetail.setStatus(SettleStatusEnum.CANCELLED);
            this.handleRefundOrder(order);
        }
        // 如果赛事结束，进行结算
        else if (CrownConstant.FINISHED.equals(league.getStage())) {
            // 判断订单状态是否是第一次结算
            boolean isWaitSettle = SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus());
            if (isWaitSettle) {
                // 查询最新version的联赛赛果详情
                Cnd cnd = Cnd.where("league_id", "=", league.getId()).and("version", "=", league.getVersion());
                List<CrownLeagueResult> subResults = leagueResultService.query(cnd);
                league.setSubResults(subResults);
                // 计算输赢
                this.calChampionStatus(orderDetail, league);
            }
            // 全输则‘结算金额’为0
            if (SettleStatusEnum.FULL_LOSE.equals(orderDetail.getStatus())) {
                order.setResultAmount(BigDecimal.ZERO);
            }
            // 非全输
            else {
                // 中奖则计算金额
                BigDecimal resultAmount = this.calChampionProfit(order);
                order.setResultAmount(resultAmount);
                // 判断结算状态（正常结算、重新结算）
                BizTypeEnum bizType = SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus())
                        ? BizTypeEnum.BALL_RESULT : BizTypeEnum.BALL_RESETTLE;
                // 划转钻石
                recordService.add(order.getUserId(), resultAmount, bizType, order.getId());
            }
            order.setStatus(isWaitSettle ? SettleStatusEnum.SETTLED : SettleStatusEnum.RESETTLED);
            // 更新orderDetail状态
            orderDetailService.update(orderDetail);
            //设置结算时间
            order.setSettleAt(System.currentTimeMillis() / 1000);
            // 更新order结算金额和结算状态
            orderService.update(order);
        } else {
            throw new BizException("结算错误：联赛状态错误(" + league.getStage() + ")。LeagueId:" + league.getId());
        }
    }

    /**
     * 综合订单结算
     *
     * @param order
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void complexSettle(CrownOrder order) {
        // 综合结算。查询出该笔订单下的orderDetail集合
        List<CrownOrderDetail> orderDetails = orderDetailService.query(Cnd.where("orderId", "=", order.getId()));
        if (orderDetails.size() < 3 || orderDetails.size() > 10) {
            throw new BizException("综合类订单结算错误，订单条目有误。数量：" + orderDetails.size() + "orderId:" + order.getId());
        }
        order.setDetails(orderDetails);
        // 赛事状态为‘other’的订单数量
        int otherStageNum = 0;
        // 订单结果是否是‘FULL_LOSE’的标记
        boolean flag = false;
        // 遍历集合结算
        for (CrownOrderDetail orderDetail : orderDetails) {
            CrownMatch match = matchService.fetch(orderDetail.getGameId());
            if (!(CrownConstant.FINISHED.equals(match.getStage()) || CrownConstant.OTHER.equals(match.getStage()))) {
                throw new BizException("结算错误：综合赛事状态错误(" + match.getStage() + ")。Mid:" + match.getId());
            }
            // 查询最新赛果详情
            Cnd cnd = Cnd.where("match_id", "=", match.getId()).and("version", "=", match.getVersion());
            // 查询最新version的赛果详情
            List<CrownSubResult> subResults = subResultService.query(cnd.orderBy("tag", "asc"));
            match.setSubResults(subResults);
            // 如果赛事是‘其他’状态
            if (CrownConstant.OTHER.equals(match.getStage())) {
                // 设置orderDetail状态为‘取消’
                orderDetail.setStatus(SettleStatusEnum.CANCELLED);
                // 记录赛事状态为‘other’的订单数量
                ++otherStageNum;
            } else if (CrownConstant.FINISHED.equals(match.getStage())) {
                // 计算订单条目输赢
                if (SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus())) {
                    this.calSimplexStatus(orderDetail, match);
                }
                // 腰斩
                if (SettleStatusEnum.CANCELLED.equals(orderDetail.getStatus())) {
                    ++otherStageNum;
                }
                // 如果该订单条目为‘全输’，flag置为false
                if (SettleStatusEnum.FULL_LOSE.equals(orderDetail.getStatus())) {
                    flag = true;
                }
            } else {
                throw new BizException("综合结算错误：赛事状态错误(" + match.getStage() + ")。MID:" + match.getId());
            }
        }
        // 如果订单关联的赛事状态都是‘other’，则退回本金
        if (otherStageNum == orderDetails.size()) {
            // 回退本金
            this.handleRefundOrder(order);
        } else {
            boolean isWaitSettle = SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus());
            // 如果不中奖将结算金额设置为0
            if (flag) {
                order.setResultAmount(BigDecimal.ZERO);
            } else {
                // 计算综合订单结算金额
                BigDecimal resultAmount = this.calComplexProfit(order);
                order.setResultAmount(resultAmount);
                // 判断结算状态（正常结算、重新结算）
                BizTypeEnum bizType;
                bizType = isWaitSettle ? BizTypeEnum.BALL_RESULT : BizTypeEnum.BALL_RESETTLE;
                // 划转钻石
                recordService.add(order.getUserId(), resultAmount, bizType, order.getId());
            }
            order.setStatus(isWaitSettle ? SettleStatusEnum.SETTLED : SettleStatusEnum.RESETTLED);
            //设置结算时间
            order.setSettleAt(System.currentTimeMillis() / 1000);
            // 更新orderDetail状态（批量更新）
            orderDetailService.update(orderDetails);
            // 更新order结算金额和结算状态
            orderService.update(order);
        }
    }

    /**
     * 单式订单结算
     *
     * @param order
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void simplexSettle(CrownOrder order, CrownMatch match) {
        CrownOrderDetail orderDetail = order.getDetails().get(0);
        // 赛事异常，退回下注金额
        if (CrownConstant.OTHER.equals(match.getStage())) {
            orderDetail.setStatus(SettleStatusEnum.CANCELLED);
            this.handleRefundOrder(order);
        }
        // 赛事正常或半场已过则进行结算
        else if (CrownConstant.FINISHED.equals(match.getStage()) || match.getIsHalfGone()) {
            // 判断订单状态是否是第一次结算
            boolean isWaitSettle = SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus());
            if (isWaitSettle) {
                // 查询最新version的赛事赛果详情
                Cnd cnd = Cnd.where("match_id", "=", match.getId()).and("version", "=", match.getVersion());
                List<CrownSubResult> subResults = subResultService.query(cnd.orderBy("tag", "asc"));
                match.setSubResults(subResults);
                // 计算输赢
                this.calSimplexStatus(orderDetail, match);
            }
            // 赛事腰斩（退款）
            if (SettleStatusEnum.CANCELLED.equals(orderDetail.getStatus())) {
                orderDetail.setStatus(SettleStatusEnum.CANCELLED);
                this.handleRefundOrder(order);
            }
            // 非腰斩
            else {
                // 全输则‘结算金额’为0
                if (SettleStatusEnum.FULL_LOSE.equals(orderDetail.getStatus())) {
                    order.setResultAmount(BigDecimal.ZERO);
                }
                // 非全输
                else {
                    // 中奖则计算金额
                    BigDecimal resultAmount = this.calSimplexProfit(order);
                    order.setResultAmount(resultAmount);
                    // 判断结算状态（正常结算、重新结算）
                    BizTypeEnum bizType;
                    bizType = isWaitSettle ? BizTypeEnum.BALL_RESULT : BizTypeEnum.BALL_RESETTLE;
                    // 划转钻石
                    recordService.add(order.getUserId(), resultAmount, bizType, order.getId());
                }
                // 判断order状态
                order.setStatus(isWaitSettle ? SettleStatusEnum.SETTLED : SettleStatusEnum.RESETTLED);
                // 更新orderDetail状态
                orderDetailService.update(orderDetail);
                // 设置结算时间
                order.setSettleAt(System.currentTimeMillis() / 1000);
                // 更新order结算金额和结算状态
                orderService.update(order);
            }
        } else {
            throw new BizException("单式结算错误：赛事状态错误(" + match.getStage() + ")。MID:" + match.getId());
        }
    }

    /**
     * 单式、综合玩法根据orderDetail no1计算输赢
     *
     * @param orderDetail
     * @param match
     */
    private void calSimplexStatus(CrownOrderDetail orderDetail, CrownMatch match) {
        // 处理赛果
        HashMap<String, CrownSubResult> subResultsMap = this.handleSubResults(match.getSubResults());
        // 计算orderDetail输赢
        switch (orderDetail.getNo1()) {
            // 全场独赢玩法
            case 1:
                this.fullCourtWin(orderDetail, subResultsMap.get("NO8"));
                break;
            // 全场让球玩法
            case 2:
                this.fullCourtLetBall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 全场大小玩法
            case 3:
                this.fullCourtBigOrSmall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 全场单双玩法
            case 4:
                this.fullCourtSingleOrDouble(orderDetail, subResultsMap.get("NO8"));
                break;
            // 半场独赢玩法
            case 5:
                this.firstHalfCourtWin(orderDetail, subResultsMap.get("NO4"));
                break;
            // 半场让球玩法
            case 6:
                this.halfCourtLetBall(orderDetail, subResultsMap.get("NO4"));
                break;
            // 半场大小玩法
            case 7:
                this.halfCourtBigOrSmall(orderDetail, subResultsMap.get("NO4"));
                break;
            // 半场波胆玩法
            case 8:
                this.halfCourtPd(orderDetail, subResultsMap.get("NO4"));
                break;
            // 全场波胆玩法
            case 9:
                this.fullCourtPd(orderDetail, subResultsMap.get("NO8"));
                break;
            // 半场总入球
            case 10:
                this.halfCourtInBall(orderDetail, subResultsMap.get("NO4"));
                break;
            // 全场总入球
            case 11:
                this.fullCourtInBall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 半场/全场玩法
            case 12:
                this.halfOrFullCourt(orderDetail, subResultsMap);
                break;
            // (15分钟盘口)开场 - 14:59 分钟 - 让球
            case 13:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO1"));
                break;
            // (15分钟盘口)开场 - 14:59 分钟 - 大 / 小
            case 14:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO1"));
                break;
            // (15分钟盘口)开场 - 14:59 分钟 - 独赢
            case 15:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO1"));
                break;
            // (15分钟盘口)15:00 - 29:59 分钟 - 让球
            case 16:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO2"));
                break;
            // (15分钟盘口)15:00 - 29:59 分钟 - 大 / 小
            case 17:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO2"));
                break;
            // (15分钟盘口)15:00 - 29:59 分钟 - 独赢
            case 18:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO2"));
                break;
            // (15分钟盘口)30:00 分钟 - 半场 - 让球
            case 19:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO3"));
                break;
            // (15分钟盘口)30:00 分钟 - 半场 - 大 / 小
            case 20:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO3"));
                break;
            // (15分钟盘口)30:00 分钟 - 半场 - 独赢
            case 21:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO3"));
                break;
            // (15分钟盘口)下半场开始 - 59:59 分钟 - 让球
            case 22:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO5"));
                break;
            // (15分钟盘口)下半场开始 - 59:59 分钟 - 大 / 小
            case 23:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO5"));
                break;
            // (15分钟盘口)下半场开始 - 59:59 分钟 - 独赢
            case 24:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO5"));
                break;
            // (15分钟盘口)60:00 - 74:59 分钟 - 让球
            case 25:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO6"));
                break;
            // (15分钟盘口)60:00 - 74:59 分钟 - 大 / 小
            case 26:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO6"));
                break;
            // (15分钟盘口)60:00 - 74:59 分钟 - 独赢
            case 27:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO6"));
                break;
            // (15分钟盘口)75:00 分钟 - 全场 - 让球
            case 28:
                this.fifteenMinLetBall(orderDetail, subResultsMap.get("NO7"));
                break;
            // (15分钟盘口)75:00 分钟 - 全场 - 大 / 小
            case 29:
                this.fifteenMinBigOrSmall(orderDetail, subResultsMap.get("NO7"));
                break;
            // (15分钟盘口)75:00 分钟 - 全场 - 独赢
            case 30:
                this.fifteenMinWin(orderDetail, subResultsMap.get("NO7"));
                break;
            // 全场双方球队进球
            case 31:
                this.fullAllTeamGoals(orderDetail, subResultsMap.get("NO8"));
                break;
            // 上半场双方球队进球
            case 32:
                this.firstHalfAllTeamGoals(orderDetail, subResultsMap.get("NO4"));
                break;
            // 下半场双方球队进球
            case 33:
                this.secondHalfAllTeamGoals(orderDetail, subResultsMap);
                break;
            // 全场球队进球数大
            case 34:
                this.fullTeamGoalsBig(orderDetail, subResultsMap.get("NO8"));
                break;
            // 全场球队进球数小
            case 35:
                this.fullTeamGoalsSmall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 半场球队进球数大
            case 36:
                this.halfTeamGoalsBig(orderDetail, subResultsMap.get("NO4"));
                break;
            // 半场球队进球数小
            case 37:
                this.halfTeamGoalsSmall(orderDetail, subResultsMap.get("NO4"));
                break;
            // 半场单双
            case 38:
                this.halfCourtSingleOrDouble(orderDetail, subResultsMap.get("NO4"));
                break;
            // 净胜球数
            case 39:
                this.goalsDifference(orderDetail, subResultsMap.get("NO8"));
                break;
            // 双重机会
            case 40:
                this.doubleChance(orderDetail, subResultsMap.get("NO8"));
                break;
            // 零失球
            case 41:
                this.zeroLose(orderDetail, subResultsMap.get("NO8"));
                break;
            // 零失球获胜
            case 42:
                this.zeroLoseAndWin(orderDetail, subResultsMap.get("NO8"));
                break;
            // 独赢 & 进球 大 / 小
            case 43:
                this.fullCourtWinAndBigSmall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 独赢 & 双方球队进球
            case 44:
                this.fullCourtWinAndAllTeamGoals(orderDetail, subResultsMap.get("NO8"));
                break;
            // 最多进球的半场
            case 45:
                this.halfMostGoals(orderDetail, subResultsMap);
                break;
            // 最多进球的半场 - 独赢
            case 46:
                this.halfCourtMostGoalsWin(orderDetail, subResultsMap);
                break;
            // 双半场进球
            case 47:
                this.doubleHalfCourtGoals(orderDetail, subResultsMap);
                break;
            // 双重机会 & 进球 大 / 小
            case 48:
                this.doubleChanceAndBigSmall(orderDetail, subResultsMap.get("NO8"));
                break;
            // 双重机会 & 双方球队进球
            case 49:
                this.doubleChanceAndAllTeamGoals(orderDetail, subResultsMap.get("NO8"));
                break;
            // 进球 大 / 小 & 进球 单 / 双
            case 50:
                this.goalsBigSmallAndSingleDouble(orderDetail, subResultsMap.get("NO8"));
                break;
            // 赢得任一半场
            case 51:
                this.winAnyHalfCourt(orderDetail, subResultsMap);
                break;
            // 赢得所有半场
            case 52:
                this.winAllHalfCourt(orderDetail, subResultsMap);
                break;
            default:
                throw new BizException("结算错误：玩法不存在！" + orderDetail.getNo1());
        }
    }

    /**
     * 冠军输赢计算
     *
     * @param orderDetail
     * @param league
     */
    private void calChampionStatus(CrownOrderDetail orderDetail, CrownLeague league) {
        // 取赛果集合中的‘冠军名’
        List<String> results = league.getSubResults()
                .stream()
                .map(CrownLeagueResult::getWinner)
                .collect(Collectors.toList());
        if (results.contains(orderDetail.getCoeWord())) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        } else {
            orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
        }
    }


    /**
     * 处理退款订单
     *
     * @param order
     */
    private void handleRefundOrder(CrownOrder order) {
        List<CrownOrderDetail> orderDetails = order.getDetails();
        if (SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus())) {
            order.setStatus(SettleStatusEnum.CANCELLED);
        }
        // 更新orderDetail状态（如果是综合订单会批量更新所有的订单条目）
        orderDetailService.update(orderDetails);
        // 设置结算时间
        order.setSettleAt(System.currentTimeMillis() / 1000);
        // 更新order结算金额和结算状态
        orderService.update(order);
        // 判断结算状态（正常结算、重新结算）
        BizTypeEnum status = SettleStatusEnum.WAIT_SETTLE.equals(order.getStatus())
                ? BizTypeEnum.BALL_REVERT : BizTypeEnum.BALL_RESETTLE;
        // 钻石划转
        recordService.add(order.getUserId(), order.getAmount(), status, order.getId());
    }

    /**
     * 处理赛果详情数据，将list转为map，key为subResult对象的tag(NO1、NO2...)
     *
     * @param subResults
     * @return
     */
    private HashMap<String, CrownSubResult> handleSubResults(List<CrownSubResult> subResults) {
        HashMap<String, CrownSubResult> map = new HashMap<>(subResults.size());
        for (CrownSubResult subResult : subResults) {
            map.put(subResult.getTag(), subResult);
        }
        return map;
    }

    /**
     * 处理主客队比分，如果为腰斩设置orderDetail状态为CANCELLED
     *
     * @param orderDetail
     * @param subResult
     * @return
     */
    private Map<String, Integer> handleScores(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        if (subResult.getResultH().contains("腰斩") || subResult.getResultC().contains("腰斩")) {
            orderDetail.setStatus(SettleStatusEnum.CANCELLED);
            return null;
        } else {
            Map<String, Integer> scoreMap = new HashMap<>();
            scoreMap.put("H", Integer.parseInt(subResult.getResultH()));
            scoreMap.put("C", Integer.parseInt(subResult.getResultC()));
            return scoreMap;
        }
    }


    /**
     * 全场独赢玩法结算
     *
     * @param orderDetail
     */
    private void fullCourtWin(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtWin(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 独赢玩法输赢计算
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void courtWin(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // no3是下注的内容。(取绝对值，因为复合玩法中no3有负数)
        int no3 = Math.abs(orderDetail.getNo3());
        // 如果no3 = 1 主队比分 > 客队比分 中奖
        if (1 == no3 && (mbInBall > tgInBall)) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        }
        // 如果no3 = 2 客队比分 > 主队比分 中奖
        else if (2 == no3 && (tgInBall > mbInBall)) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        }
        // 如果no3 = 3 客队比分 = 主队比分 中奖
        else if (3 == no3 && (tgInBall == mbInBall)) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        }
        // 否则 全输
        else {
            orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
        }
    }


    /**
     * 全场让球玩法结算
     *
     * @param orderDetail
     */
    private void fullCourtLetBall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 计算输赢
            this.courtLetBall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 让球玩法输赢计算
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void courtLetBall(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 获取下注的点
        int no3 = orderDetail.getNo3();
        boolean mbIsStrong = (1 == orderDetail.getNo3() && !orderDetail.getCoeNum().contains("-"))
                || (2 == orderDetail.getNo3() && orderDetail.getCoeNum().contains("-"));
        // 主队是强队
        if (mbIsStrong) {
            // 单系数
            if (!orderDetail.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(orderDetail.getCoeNum()));
                // 主队得分 - 客队得分 - 系数 > 0
                if (mbInBall - tgInBall - coeNum > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    } else {
                        // 下注客队 全输
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    }
                }
                // 主队得分 - 客队得分 - 系数 = 0
                else if (mbInBall - tgInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    orderDetail.setStatus(SettleStatusEnum.GO_WATER);
                }
                // 主队得分 - 客队得分 - 系数 < 0
                else {
                    // 下注主队 全输
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    } else {
                        // 下注客队 全赢
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(orderDetail.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(orderDetail.getCoeNum().split("/")[1]));
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 > 0
                if (mbInBall - tgInBall - coeNumOne > 0 && mbInBall - tgInBall - coeNumTwo > 0) {
                    // 下注主队 全赢
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    } else {
                        // 下注客队 全输
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    }
                }
                // 主队得分 - 客队得分 - 系数1 > 0 && 主队得分 - 客队得分 - 系数2 = 0
                else if (mbInBall - tgInBall - coeNumOne > 0 && mbInBall - tgInBall - coeNumTwo == 0) {
                    // 下注主队 半赢
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                    } else {
                        // 下注客队 半输
                        orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                    }
                }
                // 主队得分 - 客队得分 - 系数1 == 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbInBall - tgInBall - coeNumOne == 0 && mbInBall - tgInBall - coeNumTwo < 0) {
                    // 下注主队 半输
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                    } else {
                        // 下注客队 半赢
                        orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                    }
                }
                // 主队得分 - 客队得分 - 系数1 < 0 && 主队得分 - 客队得分 - 系数2 < 0
                else if (mbInBall - tgInBall - coeNumOne < 0 && mbInBall - tgInBall - coeNumTwo < 0) {
                    // 下注主队 全输
                    if (1 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    } else {
                        // 下注客队 全赢
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        } else {
            // 客队是强队
            // 单系数
            if (!orderDetail.getCoeNum().contains("/")) {
                double coeNum = Math.abs(Double.parseDouble(orderDetail.getCoeNum()));
                // 客队得分 - 主队得分 - 系数 > 0
                if (tgInBall - mbInBall - coeNum > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    } else {
                        // 下注主队 全输
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    }
                }
                // 客队得分 - 主队得分 - 系数 = 0
                else if (tgInBall - mbInBall - coeNum == 0) {
                    // 下注主队 走水.下注客队 走水
                    orderDetail.setStatus(SettleStatusEnum.GO_WATER);
                }
                // 客队得分 - 主队得分 - 系数 < 0
                else {
                    // 下注客队 全输
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    } else {
                        // 下注主队 全赢
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    }
                }
            } else {
                // 双系数(如"0.5 / 1")
                double coeNumOne = Math.abs(Double.parseDouble(orderDetail.getCoeNum().split("/")[0]));
                double coeNumTwo = Math.abs(Double.parseDouble(orderDetail.getCoeNum().split("/")[1]));
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 > 0
                if (tgInBall - mbInBall - coeNumOne > 0 && tgInBall - mbInBall - coeNumTwo > 0) {
                    // 下注客队 全赢
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    } else {
                        // 下注主队 全输
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    }
                }
                // 客队得分 - 主队得分 - 系数1 > 0 && 客队得分 - 主队得分 - 系数2 = 0
                else if (tgInBall - mbInBall - coeNumOne > 0 && tgInBall - mbInBall - coeNumTwo == 0) {
                    // 下注客队 半赢
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                    } else {
                        // 下注主队 半输
                        orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                    }
                }
                // 客队得分 - 主队得分 - 系数1 == 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgInBall - mbInBall - coeNumOne == 0 && tgInBall - mbInBall - coeNumTwo < 0) {
                    // 下注客队 半输
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                    } else {
                        // 下注主队 半赢
                        orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                    }
                }
                // 客队得分 - 主队得分 - 系数1 < 0 && 客队得分 - 主队得分 - 系数2 < 0
                else if (tgInBall - mbInBall - coeNumOne < 0 && tgInBall - mbInBall - coeNumTwo < 0) {
                    // 下注客队 全输
                    if (2 == no3) {
                        orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                    } else {
                        // 下注主队 全赢
                        orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                    }
                }
                // 否则 系数可能有误
                else {
                    throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
                }
            }
        }
    }

    /**
     * 全场大小玩法结算
     *
     * @param orderDetail
     */
    private void fullCourtBigOrSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtBigOrSmall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 大小玩法计算输赢
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void courtBigOrSmall(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 获取下注内容大、小
        String coeWord = orderDetail.getCoeWord();
        if (coeWord.contains("&")) {
            coeWord = coeWord.split("&")[1];
        }
        // 得分 = 主队得分 + 客队得分
        int courtInBall = mbInBall + tgInBall;
        // 单系数
        String coeNumStr = orderDetail.getCoeNum();
        if (!coeNumStr.contains("/")) {
            double coeNum = Double.parseDouble(coeNumStr);
            // 得分大于系数
            if (courtInBall > coeNum) {
                // 下注‘大’ 全赢
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 下注‘小’ 全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
            // 得分小于系数
            else if (courtInBall < coeNum) {
                // 下注‘大’ 全输
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                } else {
                    // 下注‘小’ 全赢
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
            }
            // 得分等于系数，走水。
            else {
                orderDetail.setStatus(SettleStatusEnum.GO_WATER);
            }
        } else {
            // 双系数
            double coeNumOne = Double.parseDouble(coeNumStr.split("/")[0]);
            double coeNumTwo = Double.parseDouble(coeNumStr.split("/")[1]);
            // 得分 > 系数1 && 得分 > 系数2
            if (courtInBall > coeNumOne && courtInBall > coeNumTwo) {
                // 下注‘大’ 全赢
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 下注‘小’ 全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
            // 得分 > 系数1 && 得分 = 系数2
            else if (courtInBall > coeNumOne && courtInBall == coeNumTwo) {
                // 下注‘大’ 半赢
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                } else {
                    // 下注‘小’ 半输
                    orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                }
            }
            // 得分 == 系数1 && 得分 < 系数2
            else if (courtInBall == coeNumOne && courtInBall < coeNumTwo) {
                // 下注‘大’ 半输
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
                } else {
                    // 下注no3=2 半赢
                    orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
                }
            }
            // 得分 < 系数1 && 得分 < 系数2
            else if (courtInBall < coeNumOne && courtInBall < coeNumTwo) {
                // 下注‘大’ 全输
                if ("大".equals(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                } else {
                    // 下注‘小’ 全赢
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
            }
            // 否则 系数可能有误
            else {
                throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
            }
        }
    }

    /**
     * 全场单双玩法结算
     *
     * @param orderDetail
     */
    private void fullCourtSingleOrDouble(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtSingleOrDouble(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 单双输赢计算
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void courtSingleOrDouble(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 获取下注的点(复合玩法中no3有负数，所以取绝对值)
        int no3 = Math.abs(orderDetail.getNo3());
        // 全场比分为单数时
        if ((mbInBall + tgInBall) % 2 == 1) {
            // 下注no3=1的位置 全赢
            if (1 == no3) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            } else {
                // 下注no3=2的位置 全输
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        } else {
            // 全场比分为双数时
            // 下注no3=2的位置 全赢
            if (2 == no3) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            } else {
                // 下注no3=1的位置 全输
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        }
    }

    /**
     * 上半场独赢玩法结算
     *
     * @param orderDetail
     */
    private void firstHalfCourtWin(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtWin(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 下半场独赢玩法计算
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void secondHalfCourtWin(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取上半场比分
        CrownSubResult halfSubResult = subResultsMap.get("NO4");
        Map<String, Integer> halfScoresMap = this.handleScores(orderDetail, halfSubResult);
        if (null != halfScoresMap) {
            int mbFirstHalfInBall = halfScoresMap.get("H");
            int tgFirstHalfInBall = halfScoresMap.get("C");
            // 获取全场比分
            CrownSubResult fullSubResult = subResultsMap.get("NO8");
            Map<String, Integer> fullScoresMap = this.handleScores(orderDetail, fullSubResult);
            if (null != fullScoresMap) {
                // 得到主客队下半场比分
                int mbSecondHalfInBall = fullScoresMap.get("H") - mbFirstHalfInBall;
                int tgSecondHalfInBall = fullScoresMap.get("C") - tgFirstHalfInBall;
                // 计算下半场独赢
                this.courtWin(orderDetail, mbSecondHalfInBall, tgSecondHalfInBall);
            }
        }
    }

    /**
     * 半场让球玩法结算
     *
     * @param orderDetail
     */
    private void halfCourtLetBall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtLetBall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 半场大小玩法结算
     *
     * @param orderDetail
     */
    private void halfCourtBigOrSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtBigOrSmall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 半场波胆玩法结算
     * 1-0 0-1 1-1 2-0 0-2 2-1 1-2 2-2...3-3 其他
     *
     * @param orderDetail
     */
    private void halfCourtPd(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtPd(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 全场波胆玩法结算
     * 1-0 0-1 1-1 2-0 0-2 2-1 1-2 2-2...4-4 其他
     *
     * @param orderDetail
     */
    private void fullCourtPd(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtPd(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 波胆玩法输赢计算
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void courtPd(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 半场波胆8，比分截止到3-3。 全场波胆9，比分截止到4-4。
        int value = 0;
        switch (orderDetail.getNo1()) {
            case 8:
                value = 3;
                break;
            case 9:
                value = 4;
                break;
            default:
                throw new BizException("波胆玩法no1错误");
        }

        // 如果下注的是‘其他’(no1:8|9 no2:0 no3:0)
        if (0 == orderDetail.getNo2() && 0 == orderDetail.getNo3()) {
            // 如果赛果比分也是属于‘其他’范畴 则全赢
            if (mbInBall > value || tgInBall > value) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            } else {
                // 赛果比分不属于‘其他’范畴 则全输
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        } else {// 下注的是具体比分
            // 切割出下注的主队上半场比分
            int mbBetBall = Integer.parseInt(orderDetail.getCoeWord().split("-")[0]);
            // 切割出下注的客队上半场比分
            int tgBetBall = Integer.parseInt(orderDetail.getCoeWord().split("-")[1]);
            // 如果下注比分和赛果比分相同则 全赢
            if (mbBetBall == mbInBall && tgBetBall == tgInBall) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            } else {
                // 如果下注比分和赛果比分不同则 全输
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        }

    }

    /**
     * 半场总入球玩法结算
     * 0 1 2 3+
     *
     * @param orderDetail
     */
    private void halfCourtInBall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 获取下注的coeWord
            String coeWord = orderDetail.getCoeWord();
            // 半场主队客队总进球数: mbHalfInBall + tgHalfInBall
            int allHalfInBall = scoresMap.get("H") + scoresMap.get("C");
            // 当下注的是3+(亚博上下注时写的‘3或以上’。所以说3+包含3)
            if (coeWord.contains("+")) {
                // 判断赛果总入球大于该下注系数文字则 全赢
                if (allHalfInBall >= Integer.parseInt(coeWord.replace("+", ""))) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 否则全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            } else {
                // 当下注的是其他值时，数值与入球相同则 全赢
                if (allHalfInBall == Integer.parseInt(coeWord)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 不相同则 全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
        }
    }


    /**
     * 全场总入球玩法结算
     * 0~1 2~3 4~6 7+
     *
     * @param orderDetail
     */
    private void fullCourtInBall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 获取下注的coeWord
            String coeWord = orderDetail.getCoeWord();
            // 半场主队客队总进球数: mbInBall + tgInBall
            int allFullInBall = scoresMap.get("H") + scoresMap.get("C");
            // 当下注的是7+（亚博上下注时写的‘7或以上’，所以7+包含7）
            if (coeWord.contains("+")) {
                // 判断赛果总入球大于等于该下注系数文字则 全赢
                if (allFullInBall >= Integer.parseInt(coeWord.replace("+", ""))) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 否则全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            } else {
                // 切割系数(0~1或2~3或4~6)
                double preCoeWord = Double.parseDouble(coeWord.split("~")[0]);
                double nextCoeWord = Double.parseDouble(coeWord.split("~")[1]);
                // 当下注的是其他值时，入球在系数的区间内则 全赢
                if (preCoeWord <= allFullInBall && allFullInBall <= nextCoeWord) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    // 不相同则 全输
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
        }
    }

    /**
     * 半场/全场玩法结算
     * 主-主 主-和 主-客 和-主 和-和 和-客 客-主 客-和 客-客
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void halfOrFullCourt(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取主客队半场比分
        Map<String, Integer> halfScoreMap = this.handleScores(orderDetail, subResultsMap.get("NO4"));
        Map<String, Integer> fullScoreMap = this.handleScores(orderDetail, subResultsMap.get("NO8"));
        if (null != halfScoreMap && null != fullScoreMap) {
            // 计算上半场输赢
            this.courtWin(orderDetail, halfScoreMap.get("H"), halfScoreMap.get("C"));
            // 如果计算半场的结果为‘全赢’，再计算全场输赢
            if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
                // 将no2值赋值给no3
                int no3 = orderDetail.getNo3();
                orderDetail.setNo3(orderDetail.getNo2());
                this.courtWin(orderDetail, fullScoreMap.get("H"), fullScoreMap.get("C"));
                orderDetail.setNo3(no3);
            }
        }
    }


    /**
     * 15分钟各阶段让球
     *
     * @param orderDetail
     */
    private void fifteenMinLetBall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        if (null == subResult) {
            throw new BizException("15分钟赛果不存在。赛事id：" + orderDetail.getGameId());
        }
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtLetBall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 15分钟各阶段大小
     *
     * @param orderDetail
     */
    private void fifteenMinBigOrSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        if (null == subResult) {
            throw new BizException("15分钟赛果不存在。赛事id：" + orderDetail.getGameId());
        }
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtBigOrSmall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 15分钟各阶段独赢
     *
     * @param orderDetail
     */
    private void fifteenMinWin(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        if (null == subResult) {
            throw new BizException("15分钟赛果不存在，阶段。赛事id：" + orderDetail.getGameId());
        }
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtWin(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 全场双方球队进球
     *
     * @param orderDetail
     */
    private void fullAllTeamGoals(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.allTeamGoals(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }


    /**
     * 上半场双方球队进球
     *
     * @param orderDetail
     */
    private void firstHalfAllTeamGoals(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.allTeamGoals(orderDetail, scoresMap.get("H"), scoresMap.get("C"));

        }
    }

    /**
     * 下半场双方球队进球
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void secondHalfAllTeamGoals(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取上半场比分
        CrownSubResult halfSubResult = subResultsMap.get("NO4");
        Map<String, Integer> halfScoresMap = this.handleScores(orderDetail, halfSubResult);
        if (null != halfScoresMap) {
            int mbFirstHalfInBall = halfScoresMap.get("H");
            int tgFirstHalfInBall = halfScoresMap.get("C");
            // 获取全场比分
            CrownSubResult fullSubResult = subResultsMap.get("NO8");
            Map<String, Integer> fullScoresMap = this.handleScores(orderDetail, fullSubResult);
            if (null != fullScoresMap) {
                // 主客队下半场比分
                int mbSecondHalfInBall = fullScoresMap.get("H") - mbFirstHalfInBall;
                int tgSecondHalfInBall = fullScoresMap.get("C") - tgFirstHalfInBall;
                this.allTeamGoals(orderDetail, mbSecondHalfInBall, tgSecondHalfInBall);
            }
        }
    }

    /**
     * 双方球队进球数输赢计算
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void allTeamGoals(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 获取下注的点
        String coeWord = orderDetail.getCoeWord();
        if (coeWord.contains("&")) {
            coeWord = coeWord.split("&")[1];
        }
        // 如果下注‘是’ 并且 双方球队有进球 则全赢
        if ("是".equals(coeWord) && (mbInBall > 0 && tgInBall > 0)) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        }
        // 下注‘不是’ 并且 双方球队没有进球 则全赢
        else if ("不是".equals(coeWord) && (mbInBall == 0 && tgInBall == 0)) {
            orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
        }
        // 否则 全输
        else {
            orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
        }
    }


    /**
     * 全场球队进球数大
     *
     * @param orderDetail
     */
    private void fullTeamGoalsBig(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.teamGoalsBig(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 半场球队进球数大
     *
     * @param orderDetail
     */
    private void halfTeamGoalsBig(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 计算输赢
            this.teamGoalsBig(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 球队进球大
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void teamGoalsBig(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 根据下注的点选择进行运算的比分
        int inBall = 1 == orderDetail.getNo3() ? mbInBall : tgInBall;
        // 单系数
        String coeNumStr = orderDetail.getCoeNum();
        if (!coeNumStr.contains("/")) {
            double coeNum = Double.parseDouble(coeNumStr);
            // 如果得分大于系数 全赢
            if (inBall > coeNum) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 如果得分小于系数 全输
            else if (inBall < coeNum) {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
            // 如果主队得分等于系数 走水
            else {
                orderDetail.setStatus(SettleStatusEnum.GO_WATER);
            }
        } else {
            // 双系数
            double coeNumOne = Double.parseDouble(coeNumStr.split("/")[0]);
            double coeNumTwo = Double.parseDouble(coeNumStr.split("/")[1]);
            // 得分 > 系数1 && 得分 > 系数2
            if (inBall > coeNumOne && inBall > coeNumTwo) {
                // 全赢
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 得分 > 系数1 && 得分 = 系数2
            else if (inBall > coeNumOne && inBall == coeNumTwo) {
                // 半赢
                orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
            }
            // 得分 = 系数1 && 得分 < 系数2
            else if (inBall == coeNumOne && inBall < coeNumTwo) {
                // 半输
                orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
            }
            // 得分 < 系数1 && 得分 < 系数2
            else if (inBall < coeNumOne && inBall < coeNumTwo) {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
            // 系数没见过
            else {
                throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
            }
        }
    }


    /**
     * 全场球队进球数小
     *
     * @param orderDetail
     */
    private void fullTeamGoalsSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 计算输赢
            this.teamGoalsSmall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 半场球队进球数小
     *
     * @param orderDetail
     */
    private void halfTeamGoalsSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.teamGoalsSmall(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 球队进球小
     *
     * @param orderDetail
     * @param mbInBall
     * @param tgInBall
     */
    private void teamGoalsSmall(CrownOrderDetail orderDetail, int mbInBall, int tgInBall) {
        // 根据下注的点选择进行运算的比分
        int inBall = 1 == orderDetail.getNo3() ? mbInBall : tgInBall;
        // 单系数
        String coeNumStr = orderDetail.getCoeNum();
        if (!coeNumStr.contains("/")) {
            double coeNum = Double.parseDouble(coeNumStr);
            // 如果得分小于系数 全赢
            if (inBall < coeNum) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 如果得分大于系数 全输
            else if (inBall > coeNum) {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
            // 如果主队得分等于系数 走水
            else {
                orderDetail.setStatus(SettleStatusEnum.GO_WATER);
            }
        } else {
            // 双系数
            double coeNumOne = Double.parseDouble(coeNumStr.split("/")[0]);
            double coeNumTwo = Double.parseDouble(coeNumStr.split("/")[1]);
            // 得分 < 系数1 && 得分 < 系数2
            if (inBall < coeNumOne && inBall < coeNumTwo) {
                // 全赢
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 得分 = 系数1 && 得分 < 系数2
            else if (inBall == coeNumOne && inBall < coeNumTwo) {
                // 半输
                orderDetail.setStatus(SettleStatusEnum.HALF_WIN);
            }
            // 得分 > 系数1 && 得分 = 系数2
            else if (inBall > coeNumOne && inBall == coeNumTwo) {
                // 半赢
                orderDetail.setStatus(SettleStatusEnum.HALF_LOSE);
            }
            // 得分 > 系数1 && 得分 > 系数2
            else if (inBall > coeNumOne && inBall > coeNumTwo) {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
            // 系数没见过
            else {
                throw new BizException("结算错误：玩法系数有误" + "coeNumOne:" + coeNumOne + "coeNumTwo:" + coeNumTwo);
            }
        }
    }


    /**
     * 半场单双
     *
     * @param orderDetail
     */
    private void halfCourtSingleOrDouble(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            this.courtSingleOrDouble(orderDetail, scoresMap.get("H"), scoresMap.get("C"));
        }
    }

    /**
     * 净胜球
     *
     * @param orderDetail
     */
    private void goalsDifference(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            int mbInBall = scoresMap.get("H");
            int tgInBall = scoresMap.get("C");
            // 具体下注内容
            int no2 = orderDetail.getNo3();
            // 1 主胜 2客胜 3和
            int no3 = orderDetail.getNo2();
            // 如果下注和局
            if (3 == no3) {
                // 如果下注0-0和局并且比分是0-0 则全赢
                if (1 == no2 && (mbInBall == 0 && tgInBall == 0)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 如果下注‘任何进球和局’并且比分是和局 则全赢
                else if (2 == no2 && (mbInBall == tgInBall)) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                } else {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            } else {
                int goalDifference;
                // 如果no3 == 1下注主队。得到净胜球数 （主队进球 - 客队进球）
                if (1 == no3) {
                    goalDifference = mbInBall - tgInBall;
                }
                // 否则如果no3 == 3 下注客队。得到净胜球数 （客队进球 - 主队进球）
                else {
                    goalDifference = tgInBall - mbInBall;
                }
                // 如果净胜球大于等于4 并且no2=4 则全赢
                if (goalDifference >= 4 && 4 == no2) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 如果净胜球数和no2相等 则全赢
                else if (goalDifference == no2) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 其他情况全输
                else {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
        }
    }


    /**
     * 双重机会
     *
     * @param orderDetail
     */
    private void doubleChance(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            // 获取下注的点 (复合玩法中no3有的是负数，所以取绝对值)
            int no3 = Math.abs(orderDetail.getNo3());
            // 主队比分减客队比分结果
            int result = scoresMap.get("H") - scoresMap.get("C");
            // 如果result大于0 说明主队赢。下注no3=1、no3=3 全赢
            if (result > 0 && (1 == no3 || 3 == no3)) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 如果result等于0 说明和局
            else if (result == 0 && (1 == no3 || 2 == no3)) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 如果result小于0 说明客队赢
            else if (result < 0 && (2 == no3 || 3 == no3)) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 否则全输
            else {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        }
    }


    /**
     * 零失球
     *
     * @param orderDetail
     */
    private void zeroLose(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        Map<String, Integer> scoresMap = this.handleScores(orderDetail, subResult);
        if (null != scoresMap) {
            int mbInBall = scoresMap.get("H");
            int tgInBall = scoresMap.get("C");
            // 获取下注的点
            int no3 = orderDetail.getNo3();
            // 如果下注的是主队，当客队进球数为0时，全赢
            if (1 == no3 && tgInBall == 0) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 如果下注的是客队，当主队进球为0时，全赢
            else if (2 == no3 && mbInBall == 0) {
                orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
            }
            // 否则全输
            else {
                orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
            }
        }
    }


    /**
     * 零失球获胜
     *
     * @param orderDetail
     */
    private void zeroLoseAndWin(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算零失球是否全赢
        this.zeroLose(orderDetail, subResult);
        // 如果零失球条件达成，计算是否获胜
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullCourtWin(orderDetail, subResult);
        }
    }


    /**
     * 独赢 & 进球 大 / 小
     *
     * @param orderDetail
     */
    private void fullCourtWinAndBigSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算独赢
        this.fullCourtWin(orderDetail, subResult);
        // 如果独赢结果全赢，计算大小
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullCourtBigOrSmall(orderDetail, subResult);
        }
    }

    /**
     * 独赢 & 双方球队进球
     *
     * @param orderDetail
     * @param subResult
     */
    private void fullCourtWinAndAllTeamGoals(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算独赢
        this.fullCourtWin(orderDetail, subResult);
        // 如果独赢结果全赢，计算双方球队进球
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullAllTeamGoals(orderDetail, subResult);
        }
    }

    /**
     * 最多进球的半场
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void halfMostGoals(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取上半场比分
        CrownSubResult halfSubResult = subResultsMap.get("NO4");
        Map<String, Integer> halfScoresMap = this.handleScores(orderDetail, halfSubResult);
        if (null != halfScoresMap) {
            int firstHalfInBall = halfScoresMap.get("H") + halfScoresMap.get("C");
            // 获取全场比分
            CrownSubResult fullSubResult = subResultsMap.get("NO8");
            Map<String, Integer> fullScoresMap = this.handleScores(orderDetail, fullSubResult);
            if (null != fullScoresMap) {
                int fullInBall = fullScoresMap.get("H") + fullScoresMap.get("C");
                // 得到下半场比分
                int secondHalfInBall = fullInBall - firstHalfInBall;
                // 获取下注的点
                int no3 = orderDetail.getNo3();
                // 如果上半场进球数 大于 下半场进球数 并且下注 上半场 则全赢
                if (firstHalfInBall > secondHalfInBall && 1 == no3) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 如果下半场进球数 大于 上半场进球数 并且下注 下半场 则全赢
                else if (secondHalfInBall > firstHalfInBall && 2 == no3) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 否则 全输
                else {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
        }
    }


    /**
     * 最多进球的半场 - 独赢
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void halfCourtMostGoalsWin(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取上半场比分
        CrownSubResult halfSubResult = subResultsMap.get("NO4");
        Map<String, Integer> halfScoresMap = this.handleScores(orderDetail, halfSubResult);
        if (null != halfScoresMap) {
            int firstHalfInBall = halfScoresMap.get("H") + halfScoresMap.get("C");
            // 获取全场比分
            CrownSubResult fullSubResult = subResultsMap.get("NO8");
            Map<String, Integer> fullScoresMap = this.handleScores(orderDetail, fullSubResult);
            if (null != fullScoresMap) {
                int fullInBall = fullScoresMap.get("H") + fullScoresMap.get("C");
                // 得到下半场比分
                int secondHalfInBall = fullInBall - firstHalfInBall;
                // 计算独赢输赢
                this.courtWin(orderDetail, firstHalfInBall, secondHalfInBall);
            }
        }
    }


    /**
     * 双半场进球
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void doubleHalfCourtGoals(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 获取主客队上半场进球
        CrownSubResult halfSubResult = subResultsMap.get("NO4");
        Map<String, Integer> halfScoresMap = this.handleScores(orderDetail, halfSubResult);
        if (null != halfScoresMap) {
            int mbFirstHalfInBall = halfScoresMap.get("H");
            int tgFirstHalfInBall = halfScoresMap.get("C");
            // 获取主客队下半场进球
            CrownSubResult fullSubResult = subResultsMap.get("NO8");
            Map<String, Integer> fullScoresMap = this.handleScores(orderDetail, fullSubResult);
            if (null != fullScoresMap) {
                int mbSecondHalfInBall = fullScoresMap.get("H") - mbFirstHalfInBall;
                int tgSecondHalfInBall = fullScoresMap.get("C") - tgFirstHalfInBall;
                // 获取下注的点
                int no3 = orderDetail.getNo3();
                // 如果主队上半场进球 大于0 并且下半场进球 大于0 并且 下注no3 = 1 全赢
                if (1 == no3 && mbFirstHalfInBall > 0 && mbSecondHalfInBall > 0) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 如果客队上半场进球 大于0 并且下半场进球 大于0 并且 下注no3 = 2 全赢
                else if (2 == no3 && tgFirstHalfInBall > 0 && tgSecondHalfInBall > 0) {
                    orderDetail.setStatus(SettleStatusEnum.FULL_WIN);
                }
                // 否则全输
                else {
                    orderDetail.setStatus(SettleStatusEnum.FULL_LOSE);
                }
            }
        }
    }


    /**
     * 双重机会 & 进球 大 / 小
     *
     * @param orderDetail
     * @param subResult
     */
    private void doubleChanceAndBigSmall(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算双重机会输赢
        this.doubleChance(orderDetail, subResult);
        // 如果结果为全赢，接着计算进球大小
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullCourtBigOrSmall(orderDetail, subResult);
        }
    }

    /**
     * 双重机会 & 双方球队进球
     *
     * @param orderDetail
     * @param subResult
     */
    private void doubleChanceAndAllTeamGoals(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算双重机会输赢
        this.doubleChance(orderDetail, subResult);
        // 如果结果为全赢，接着计算双方球队进球
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullAllTeamGoals(orderDetail, subResult);
        }
    }


    /**
     * 进球 大 / 小 & 进球 单 / 双
     *
     * @param orderDetail
     * @param subResult
     */
    private void goalsBigSmallAndSingleDouble(CrownOrderDetail orderDetail, CrownSubResult subResult) {
        // 计算进球单双
        this.fullCourtSingleOrDouble(orderDetail, subResult);
        // 如果单双结果为全赢，计算进球大小
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.fullCourtBigOrSmall(orderDetail, subResult);
        }
    }

    /**
     * 赢得任一半场
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void winAnyHalfCourt(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 计算上半场输赢
        this.firstHalfCourtWin(orderDetail, subResultsMap.get("NO4"));
        // 如果计算结果是全输，则计算下半场
        if (SettleStatusEnum.FULL_LOSE.equals(orderDetail.getStatus())) {
            this.secondHalfCourtWin(orderDetail, subResultsMap);
        }
    }


    /**
     * 赢得所有半场
     *
     * @param orderDetail
     * @param subResultsMap
     */
    private void winAllHalfCourt(CrownOrderDetail orderDetail, HashMap<String, CrownSubResult> subResultsMap) {
        // 计算上半场输赢
        this.firstHalfCourtWin(orderDetail, subResultsMap.get("NO4"));
        // 如果计算结果是全赢，则计算下半场
        if (SettleStatusEnum.FULL_WIN.equals(orderDetail.getStatus())) {
            this.secondHalfCourtWin(orderDetail, subResultsMap);
        }
    }

    /**
     * 赔率需要加1的玩法
     */
    private List<Integer> no1List = Result.createList(2, 3, 6, 7, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 34, 35, 36, 37);

    /**
     * 单式金额计算
     * 中奖（可赢+本金）
     * 不中奖 0
     *
     * @param order
     * @return
     */
    private BigDecimal calSimplexProfit(CrownOrder order) {
        CrownOrderDetail orderDetail = order.getDetails().get(0);
        BigDecimal amount = order.getAmount();
        BigDecimal odds = orderDetail.getOdds();
        int no1 = orderDetail.getNo1();
        // 全场让球、全场大小、半场让球、半场大小、15、30、45、60、75分钟盘口的让球，大小、球队进球大小（全场，上半场）赔率要加一。
        // ‘结算金额’计算区别于‘可赢金额’的某些玩法赔率‘减一’，因为赢了要返回本金。
        if (no1List.contains(no1)) {
            odds = odds.add(BigDecimal.ONE);
        }
        // 根据orderDetail的状态计算金额
        switch (orderDetail.getStatus()) {
            case FULL_WIN:
                // 全赢：本金 * 赔率
                amount = amount.multiply(odds);
                break;
            case HALF_WIN:
                // 半赢：((赔率 - 1) / 2 + 1 ) * 本金
                amount = ((odds.subtract(BigDecimal.ONE))
                        .divide(new BigDecimal(2), RoundingMode.FLOOR)
                        .add(BigDecimal.ONE))
                        .multiply(amount);
                break;
            case HALF_LOSE:
                // 半输：金额 / 2
                amount = amount.divide(new BigDecimal(2), RoundingMode.FLOOR);
                break;
            case GO_WATER:
                // 走水，amount = amount
                break;
            default:
                throw new BizException("结算错误：类型错误:" + orderDetail.getStatus());
        }
        return amount;
    }

    /**
     * 综合金额计算
     *
     * @param order
     * @return
     */
    private BigDecimal calComplexProfit(CrownOrder order) {
        List<CrownOrderDetail> orderDetailList = order.getDetails();
        // 下注金额
        BigDecimal amount = order.getAmount();
        for (CrownOrderDetail orderDetail : orderDetailList) {
            // 根据orderDetail的状态计算金额
            switch (orderDetail.getStatus()) {
                case FULL_WIN:
                    // 全赢：本金 * 赔率
                    amount = amount.multiply(orderDetail.getOdds());
                    break;
                case HALF_WIN:
                    // 半赢：((赔率 - 1) / 2 + 1 ) * 本金
                    amount = ((orderDetail.getOdds().subtract(BigDecimal.ONE))
                            .divide(new BigDecimal(2), RoundingMode.FLOOR)
                            .add(BigDecimal.ONE))
                            .multiply(amount);
                    break;
                case HALF_LOSE:
                    // 半输：金额 / 2
                    amount = amount.divide(new BigDecimal(2), RoundingMode.FLOOR);
                    break;
                case CANCELLED:
                case GO_WATER:
                    // 走水，amount = amount
                    break;
                default:
                    throw new BizException("结算类型错误:" + orderDetail.getStatus());
            }

        }
        // 截取两位小数
        return amount.setScale(2, RoundingMode.DOWN);
    }


    /**
     * 冠军金额计算
     *
     * @param order
     * @return
     */
    private BigDecimal calChampionProfit(CrownOrder order) {
        CrownOrderDetail orderDetail = order.getDetails().get(0);
        BigDecimal amount = order.getAmount();
        BigDecimal odds = orderDetail.getOdds();
        return amount.multiply(odds);
    }
}
